from urllib.parse import urlparse, parse_qsl
from urllib.parse import quote

# 使用数组严格保持组合参数的url的顺序和值（不被转义和忽略）与原url一致

def extract_params_strict(url: str) -> list[tuple]:
    """将URL参数导出为严格模式的元组列表（保留空值）[1](@ref)

    参数：
        url: 包含查询参数的完整URL字符串

    返回：
        形如 [("key1","value1"), ("key2","")] 的元组列表
    """
    # 解析URL中的查询部分
    parsed_url = urlparse(url)
    # 提取并保留空值[1](@ref)
    return parse_qsl(parsed_url.query, keep_blank_values=True)


def build_query_string(params: list[tuple], safe: str = "") -> str:
    """严格按参数列表顺序构建查询字符串

    Args:
        params: 参数列表，格式如 [('key1','value1'), ('key2','')]
        safe: 指定不需要编码的字符（默认空字符串，按RFC 3986规范编码）

    Returns:
        编码后的查询字符串，如 'key1=val1&key2=val2'
    """
    query_parts = []
    for key, value in params:
        # 严格编码键和值（保留已编码内容）
        encoded_key = quote(str(key), safe=safe)
        encoded_value = quote(str(value), safe=safe) if value != "" else ""
        query_parts.append(f"{encoded_key}={encoded_value}")
    return "&".join(query_parts)


def construct_url(base_url: str, params: list[tuple]) -> str:
    """构造完整的URL（保留参数原始顺序和编码格式）

    Args:
        base_url: 基础URL（不含查询参数），如 'https://api.bilibili.com/x/space/wbi/acc/info'
        params: 参数列表

    Returns:
        完整的URL字符串，如 'https://api.bilibili.com/...?key1=val1&key2='
    """
    query = build_query_string(params, safe="!$&'()*+,;=:@")  # 保留JSON特殊字符
    return f"{base_url.rstrip('?')}?{query}" if query else base_url


# # 使用示例
# params = [('mid', '20841379'),
#           ('token', ''),
#           ('platform', 'web'),
#           ('web_location', '1550101'),
#           ('dm_img_list', '[]'),
#           ('dm_img_str', 'V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ'),
#           ('dm_cover_img_str', 'QU5HTEUgKEFNRCwgQU1EIFJhZGVvbihUTSkgR3JhcGhpY3MgKDB4MDAwMDE2MzYpIERpcmVjdDNEMTEgdnNfNV8wIHBzXzVfMCwgRDNEMTEpR29vZ2xlIEluYy4gKEFNRC'),
#           ('dm_img_inter', '{"ds":[],"wh":[4048,4586,100],"of":[281,562,281]}'),
#           ('w_webid', 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzcG1faWQiOiIzMzMuOTk5IiwiYnV2aWQiOiIxNkU2ODBBQy1ENjM1LTE2N0UtRTVBQi01NUUwOUJCMjQyMkI4MDYyN2luZm9jIiwidXNlcl9hZ2VudCI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xMzQuMC4wLjAgU2FmYXJpLzUzNy4zNiBFZGcvMTM0LjAuMC4wIiwiYnV2aWRfZnAiOiJiNzc2N2M0NjczNzRiYmU2ZDU5YWExZmMwNGFmMDBkNiIsImJpbGlfdGlja2V0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkluTXdNeUlzSW5SNWNDSTZJa3BYVkNKOS5leUpsZUhBaU9qRTNOREl5TmpVM01EWXNJbWxoZENJNk1UYzBNakF3TmpRME5pd2ljR3gwSWpvdE1YMC5RUVJ3UFU2cmxPWmo3TTktVFVHU0dxeVZhVzVmZXptUDI2YkNaQ3hoeGZjIiwiY3JlYXRlZF9hdCI6MTc0MjAwOTY4MSwidHRsIjo4NjQwMCwidXJsIjoiLzIwODQxMzk5P3NwbV9pZF9mcm9tPTMzMy4xMDA3LnRpYW5tYS4xLTEtMS5jbGljayIsInJlc3VsdCI6MCwiaXNzIjoiZ2FpYSIsImlhdCI6MTc0MjAwOTY4MX0.DbpNUY5qs0ZqZ7TelHgKz_pKWF0OnWLR423XLV3W585YDXrNR2LCMkZabNDIUIH3sxf169D8mUd57C_2nK9J7i5bMq8aIqD3bybwdgwCS-gxno5x5ti88HpEl7LZ52vym3Wvlag6kuyKqNZ-Trh59ZXlt0PEtw8M7mjLxB1fl26LgbHaMVf9_4yI4gZBxvbxEzbhZIYyDd4Fa-0yCcGS4aREZKkls5P5QAXdLii7nH6v4zIoq1p9anwGFsphBlC5HLB9x2UPvQMzywh8VQJgXTud_FDlMS_IuBokhmaAIPiTZlmLDLWgWu2FakM6O2pKTtMV6eHBWsCWsKKVsEs2cA'),
#           ('w_rid', '82324244b38eca589321ab14fc2deab0'),
#           ('wts', '1742009676')]
#
# base_url = "https://api.bilibili.com/x/space/wbi/acc/info"
# full_url = construct_url(base_url, params)
#
# print(full_url)


# print(extract_params_strict('https://api.bilibili.com/x/space/wbi/acc/info?mid=20841399&token=&platform=web&web_location=1550101&dm_img_list=[]&dm_img_str=V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ&dm_cover_img_str=QU5HTEUgKEFNRCwgQU1EIFJhZGVvbihUTSkgR3JhcGhpY3MgKDB4MDAwMDE2MzYpIERpcmVjdDNEMTEgdnNfNV8wIHBzXzVfMCwgRDNEMTEpR29vZ2xlIEluYy4gKEFNRC&dm_img_inter=%7B%22ds%22:[],%22wh%22:[4048,4586,100],%22of%22:[281,562,281]%7D&w_webid=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzcG1faWQiOiIzMzMuOTk5IiwiYnV2aWQiOiIxNkU2ODBBQy1ENjM1LTE2N0UtRTVBQi01NUUwOUJCMjQyMkI4MDYyN2luZm9jIiwidXNlcl9hZ2VudCI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xMzQuMC4wLjAgU2FmYXJpLzUzNy4zNiBFZGcvMTM0LjAuMC4wIiwiYnV2aWRfZnAiOiJiNzc2N2M0NjczNzRiYmU2ZDU5YWExZmMwNGFmMDBkNiIsImJpbGlfdGlja2V0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkluTXdNeUlzSW5SNWNDSTZJa3BYVkNKOS5leUpsZUhBaU9qRTNOREl5TmpVM01EWXNJbWxoZENJNk1UYzBNakF3TmpRME5pd2ljR3gwSWpvdE1YMC5RUVJ3UFU2cmxPWmo3TTktVFVHU0dxeVZhVzVmZXptUDI2YkNaQ3hoeGZjIiwiY3JlYXRlZF9hdCI6MTc0MjAwOTY4MSwidHRsIjo4NjQwMCwidXJsIjoiLzIwODQxMzk5P3NwbV9pZF9mcm9tPTMzMy4xMDA3LnRpYW5tYS4xLTEtMS5jbGljayIsInJlc3VsdCI6MCwiaXNzIjoiZ2FpYSIsImlhdCI6MTc0MjAwOTY4MX0.DbpNUY5qs0ZqZ7TelHgKz_pKWF0OnWLR423XLV3W585YDXrNR2LCMkZabNDIUIH3sxf169D8mUd57C_2nK9J7i5bMq8aIqD3bybwdgwCS-gxno5x5ti88HpEl7LZ52vym3Wvlag6kuyKqNZ-Trh59ZXlt0PEtw8M7mjLxB1fl26LgbHaMVf9_4yI4gZBxvbxEzbhZIYyDd4Fa-0yCcGS4aREZKkls5P5QAXdLii7nH6v4zIoq1p9anwGFsphBlC5HLB9x2UPvQMzywh8VQJgXTud_FDlMS_IuBokhmaAIPiTZlmLDLWgWu2FakM6O2pKTtMV6eHBWsCWsKKVsEs2cA&w_rid=82324244b38eca589321ab14fc2deab0&wts=1742009676'))